package com.wpf.springbootflux.controller;


import com.wpf.springbootflux.bean.Person;
import com.wpf.springbootflux.dao.PersonDao;
import com.wpf.springbootflux.utils.ValidUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.validation.Valid;

@Slf4j
@RestController
@RequestMapping("/person")
public class PersonController {

    // 现在的spring官方不推荐使用 @Autowired这种方式注入
    // 最好是使用构造函数的方式进行注入  这样与spring的耦合度降低
    private final PersonDao personDao;

    public PersonController(PersonDao personDao){
        this.personDao = personDao;
    }


    /**
     * 用旧的模式整体获取数据
     * @return
     */
    @GetMapping("/getAll")
    public Flux<Person> getAll(){
        log.info("用旧的模式整体获取数据");
        return this.personDao.findAll();
    }

    /**
     * 用SSE一条一条的获取数据
     * @return
     */
    @GetMapping(value = "/flux/getAll",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Person> getFluxAll(){
        log.info("用SSE一条一条的获取数据");
        return this.personDao.findAll();
    }


    /**
     * spring data jpa 更新和添加数据都是  save
     *     通过ID判断操作类型
     * @param person
     * @return
     */
    @PostMapping("/save")
    public Mono<Person> save(@Valid @RequestBody Person person){
        person.setId(null);
        ValidUtil.validVale(person);
        return this.personDao.save(person);
    }


    @DeleteMapping("/delete/{id}")
    public Mono<ResponseEntity<Void>> delete(@PathVariable("id") String id){

        //deleteById  没有返回值的  不知道有没有删除成功  也不知道是不是有这个数据 或者是否删除失败
//        Mono<Void> voidMono = this.personDao.deleteById(id);

        //这时候就需要先把数据查询回来  然后进行删除
        // 这时候我们可以用  链式操作来一步到位完成
        return
                //查询回来数据
                this.personDao.findById(id)
                //如果要操作数据  并且换位Mono  就使用 flatMap    如果不操作数据  就使用 map 只是对数据坐做一个转换
                .flatMap( person ->
                    this.personDao.delete(person)
                .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK))))
                //如果数据不存在的话  就返回 404
                .defaultIfEmpty(new ResponseEntity<Void>(HttpStatus.NOT_FOUND))
                ;
    }

    @GetMapping("/getById/{id}")
    public Mono<ResponseEntity<Person>> findPersonById(@PathVariable("id") String id){

        return this.personDao.findById(id)
                .map(p -> new ResponseEntity<>(p, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));

    }


    @PostMapping("/update/{id}")
    public Mono<ResponseEntity<Person>> update(@PathVariable("id") String id,
                                              @Valid @RequestBody Person person){
        ValidUtil.validVale(person);
        return this.personDao.findById(id)
                .flatMap(p -> {
                    p.setAge(person.getAge());
                    p.setName(person.getName());
                    return this.personDao.save(p);
                })
                .map(p->new ResponseEntity<>(p,HttpStatus.OK
                ))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)
                )
                ;
    }


    @GetMapping("/findByAge/{start}/{end}")
    public Flux<Person> findByAge(@PathVariable("start")int start,
                                  @PathVariable("end")int end){
        return this.personDao.findByAgeBetween(start,end);
    }

    @GetMapping(value = "/stream/findByAge/{start}/{end}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Person> streamFindById(@PathVariable("start")int start,
        @PathVariable("end")int end){
            return this.personDao.findByAgeBetween(start,end);
    }

    @GetMapping("/age/{start}/{end}")
    public Flux<Person> queryPerson(){
        return this.personDao.queryPerson();
    }

}